package com.idanchuang.component.just.web.swagger;

import com.idanchuang.component.base.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author yjy
 * Created at 2022/3/7 1:16 下午
 */
@WebFilter(urlPatterns = "/*", asyncSupported = true)
public class SwaggerWebFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(SwaggerWebFilter.class);
    private static final String LOGIN_FLAG = "swaggerLogin";

    @Autowired
    private SwaggerConfigBean swaggerConfigBean;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            if (!swaggerConfigBean.isNeedLogin()) {
                chain.doFilter(request, response);
                return;
            }
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
            String url = req.getRequestURI();
            // 处理登入
            if (url.endsWith("/swagger/login")) {
                handleLogin(req, res);
                return ;
            }
            // 非swagger相关请求， 跳过
            if (!url.endsWith("/swagger-ui.html")
                    && !url.endsWith("/doc.html")
                    && !url.endsWith("/v2/api-docs")
            ) {
                chain.doFilter(request, response);
                return;
            }
            HttpSession session = req.getSession();
            Object swaggerLogin = session.getAttribute("swaggerLogin");
            if (swaggerLogin != null && Boolean.parseBoolean(swaggerLogin.toString())) {
                // 已登入 跳过
                chain.doFilter(request, response);
                return;
            }
            // 根据cookie中的信息校验
            if (handleLoginWithCookie(req)) {
                chain.doFilter(request, response);
                return;
            }
            String requestedWith = req.getHeader("X-Requested-With");
            if (!req.getMethod().equalsIgnoreCase(HttpMethod.GET.name())
                    || "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
                // 非GET 或 异步请求 返回json
                JsonResult<Void> result = JsonResult.failure("未登入，无法访问swagger");
                res.setStatus(HttpServletResponse.SC_OK);
                res.setContentType("application/json;charset=UTF-8");
                res.getWriter().write(result.toJsonString());
                res.flushBuffer();
                return;
            }
            // GET请求 返回登入页
            res.setStatus(HttpServletResponse.SC_OK);
            res.setContentType("text/html;charset=UTF-8");
            res.getWriter().write(loginPage(req));
            res.flushBuffer();
        } catch (Exception e) {
            logger.warn("SwaggerWebFilter doFilter failed", e);
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

    private boolean handleLoginWithCookie(HttpServletRequest req) {
        Cookie[] cookies = req.getCookies();
        if (cookies == null) {
            return false;
        }
        String username = null;
        String password = null;
        for (Cookie cookie : cookies ) {
            if ("swgu".equalsIgnoreCase(cookie.getName())) {
                username = cookie.getValue();
            }
            if ("swgp".equalsIgnoreCase(cookie.getName())) {
                password = cookie.getValue();
            }
        }
        if (swaggerConfigBean.getUsername().equals(username)
                && swaggerConfigBean.getPassword().equals(password)) {
            req.getSession().setAttribute(LOGIN_FLAG, "true");
            return true;
        }
        return false;
    }

    private void handleLogin(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.setStatus(HttpServletResponse.SC_OK);
        res.setContentType("application/json;charset=UTF-8");
        JsonResult<Void> jsonResult;

        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (swaggerConfigBean.getUsername().equals(username)
                && swaggerConfigBean.getPassword().equals(password)) {
            req.getSession().setAttribute(LOGIN_FLAG, "true");
            jsonResult = JsonResult.OK;
        } else {
            jsonResult = JsonResult.failure("用户名或密码错误");
        }
        res.getWriter().write(jsonResult.toJsonString());
        res.flushBuffer();
    }

    /**
     * 登入页
     * @param request ..
     * @return ..
     */
    private static String loginPage(HttpServletRequest request) {
        String server = "http://" + request.getServerName() + ":" + request.getServerPort();
        if (request.getContextPath() != null && !request.getContextPath().isEmpty()) {
            server += request.getContextPath();
        }
        return "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Swagger 登入</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "\n" +
                "<style>\n" +
                "    #loginForm {\n" +
                "        margin: 100px auto 0 auto;\n" +
                "        text-align: center;\n" +
                "        font-size: 20px;\n" +
                "\n" +
                "    }\n" +
                "    #loginForm>input {\n" +
                "        height: 30px;\n" +
                "        line-height: 30px;\n" +
                "        margin-bottom: 10px;\n" +
                "        width: 400px;\n" +
                "    }\n" +
                "    #loginForm>button {\n" +
                "        height: 40px;\n" +
                "        line-height: 40px;\n" +
                "        margin-bottom: 10px;\n" +
                "        width: 400px;\n" +
                "        margin-left: 60px;\n" +
                "        background-color: cadetblue;\n" +
                "        border: 0;\n" +
                "        font-size: 20px;\n" +
                "        color: white;\n" +
                "        cursor: pointer;\n" +
                "    }\n" +
                "</style>\n" +
                "\n" +
                "<form id=\"loginForm\">\n" +
                "    <label>登 入 Swagger</label><br/><br/>\n" +
                "    用户：<input type=\"text\" name=\"username\" id=\"username\" /><br/>\n" +
                "    密码：<input type=\"password\" name=\"password\" id=\"password\" /><br/>\n" +
                "    <button type=\"button\" onclick=\"doSubmit()\">登入</button>\n" +
                "</form>" +
                "\n" +
                "<script type=\"application/javascript\">\n" +
                "\n" +
                "  function doSubmit() {\n" +
                "    let username = document.getElementById(\"username\").value;\n" +
                "    let password = document.getElementById(\"password\").value;\n" +
                "    if (!username || !password) {\n" +
                "      alert(\"请输入用户名与密码！\")\n" +
                "      return false;\n" +
                "    }\n" +
                "    let ajax = new XMLHttpRequest();\n" +
                "    ajax.open('get','"+  server +"/swagger/login?username='+username + '&password='+password);\n" +
                "    ajax.send();\n" +
                "    ajax.onreadystatechange = function () {\n" +
                "      if (ajax.readyState===4 &&ajax.status===200) {\n" +
                "        let result = JSON.parse(ajax.responseText);\n" +
                "        if (result.code === 0) {\n" +
                "            let exp = new Date();\n" +
                "            exp.setTime(exp.getTime() + 7200000);\n" +
                "            let expires = exp.toGMTString();\n" +
                "            document.cookie = \"swgu=\" + username + \";expires=\"+ expires;\n" +
                "            document.cookie = \"swgp=\" + password + \";expires=\"+ expires;\n" +
                "          window.open(\""+request.getRequestURI()+"\", \"_self\")\n" +
                "          return;\n" +
                "        }\n" +
                "        alert(\"登入失败：\" + result.msg);\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "\n" +
                "</script>\n" +
                "\n" +
                "</body>\n" +
                "</html>";
    }

    public SwaggerConfigBean getSwaggerConfigBean() {
        return swaggerConfigBean;
    }

    public void setSwaggerConfigBean(SwaggerConfigBean swaggerConfigBean) {
        this.swaggerConfigBean = swaggerConfigBean;
    }
}
